# @Author moxiao1995071310
import time
import pickle
import os
import re
from subprocess import call
from multiprocessing import Process, Lock

Lockd = Lock()


def read_config():
    """
        读取本地的config文件的内容
    :return: dict格式
    """
    config = {}
    with open('config', 'r') as f:
        while True:
            line = f.readline()
            if line:
                line_tuple = line.split('=')
                if len(line_tuple) == 2:
                    key, val = line_tuple
                    config[key] = val.replace('\n', '')
            else:
                break
    return config


def read_files_by_path(path, compiler_config=None, file_paths=None):
    """
        读取要编译的文件路径和编译的配置文件Test.txt文件的内容
    :param path: 父目录
    :param compiler_config:读取的Test.txt的内容
    :param file_paths:读取的文件路径内容
    :return:(compiler_config,file_paths)
    """
    if os.path.exists(path) and os.path.isdir(path):
        if compiler_config:
            compiler_config_ = compiler_config
        else:
            compiler_config_ = {}
        if file_paths:
            file_paths_ = file_paths
        else:
            file_paths_ = []
        filelist = os.listdir(path)  # 该文件夹下所有的文件（包括文件夹）
        for file in filelist:  # 遍历所有文件
            if file == 'Text.txt':  # 此时匹配到了我们的配置文件
                file_path = path + '/' + file
                with open(file_path, 'r') as f:
                    while True:
                        line = f.readline()
                        if line:
                            line_tuple = line.split('=')
                            if len(line_tuple) == 2:
                                key, val = line_tuple
                                if key:
                                    compiler_config_[key] = val.replace('\n', '')
                        else:
                            break

            elif file == 'bin' or file == 'obj':  # 排除这两个文件夹
                continue
            elif '.c' in file:
                if re.search('.*.c$', file).group(0):  # 此时匹配到了我们想要的文件
                    file_path = path + '/' + file
                    file_paths_.append(file_path)
            else:
                compiler_config_, file_paths_ = read_files_by_path(path + '/' + file, compiler_config_, file_paths_)
        return compiler_config_, file_paths_
    return compiler_config, file_paths


def execute_compiler(file_path, out_path, args=None):
    """
        执行编译
    :param file_path: 要编译的文件名
    :param out_path: 编译输出的文件
    :param args: 编译添加的参数
    :return:
    """

    compiler_command_str = ['gcc', file_path, '-o', out_path, '-lwiringPi']
    if args:
        compiler_command_str.extend(args)
    print(' '.join(compiler_command_str))
    try:
        val = call(compiler_command_str)
    except FileNotFoundError as s:
        print(s.args)
    else:
        print(val)


def execute_command(file_path, out_dir):
    """
        执行该绝对路径的文件
    :param file_path: 未编译的文件路径和文件名
    :param out_dir: 编译后的为文件夹名
    :return:
    """
    file_path_split = file_path.split('/')
    name = file_path_split[-1].replace('.c', '')
    compiler_command_str = [out_dir + '/' + name]
    print(' '.join(compiler_command_str))
    try:
        val = call(compiler_command_str)
    except FileNotFoundError as e:
        print(e.args)
    else:
        print(val)


def classify_compiler_config(compiler_config):
    """
        给compiler_config分类
    :param compiler_config:
    :return:
    """
    compiler_args_dict = {}
    compiler_dict = {}
    for item in compiler_config.items():
        key, val = item
        if re.search('-args$', key):
            name = re.search('(.*)-args$', key)
            name = name.group(1)
            compiler_args_dict[name] = val
        else:
            compiler_dict[key] = int(val)
    return compiler_dict, compiler_args_dict


config = read_config()
print(config)


def main():
    if config:
        compiler_config, file_paths = read_files_by_path(config['project_home_dir'])
        if not os.path.exists(config['out_dir']):
            os.makedirs(config['out_dir'])
        elif not os.path.isdir(config['out_dir']):
            raise Exception('该输入位置已有同名的文件存在，清检查！')
        if os.path.exists('./compiler_config.pkl'):
            compiler_pkl = None
            with open('./compiler_config.pkl', 'rb') as pick_file:
                compiler_pkl = pickle.load(pick_file)
            if compiler_pkl == compiler_config:
                time.sleep(3)  # TODO 如果 Text.txt 文件没有被修改那么这里会睡眠3秒
                return
        if compiler_config:
            with open('./compiler_config.pkl', 'wb') as pick_file:
                pickle.dump(compiler_config, pick_file)
            if file_paths:
                compiler_dict, compiler_args_dict = classify_compiler_config(compiler_config)
                for file_path in file_paths:
                    file_name = file_path.split('/')[-1].replace('.c', '')
                    if file_name in compiler_dict.keys():
                        is_compil = compiler_dict[file_name]
                        if is_compil > 0:
                            new_file_path = config['out_dir'] + '/' + file_name
                            if file_name in compiler_args_dict.keys():
                                val = compiler_args_dict[file_name]
                                if val:
                                    args = val.strip().split(' ')
                                    execute_compiler(file_path, new_file_path, args)
                            else:
                                execute_compiler(file_path, new_file_path)

                for item in compiler_dict.items():
                    key, val = item
                    if val == 2:
                        for file_path in file_paths:
                            if re.search(key + '.c$', file_path):
                                execute_command(file_path, config['out_dir'])


def run():
    """
        线程执行的方法
        :return: None
    """
    while True:
        if True:
            # 增加一个执行方法的异常处理
            try:
                Lockd.acquire()
                thread_test = Process(target=main)
                thread_test.start()
                thread_test.join(timeout=15)
                time.sleep(0.003)
                if thread_test.is_alive():
                    print('超时15秒后马上杀掉进程 进行下次拉取')
                    thread_test.terminate()
                Lockd.release()
                time.sleep(1)
            except TimeoutError as e:
                print('task timeout')
            except Exception as e:
                print('unknow error:', e)


if __name__ == '__main__':
    run()
